/**
 * Copyright (c) 2009 Blue Whale Systems Ltd
 * 
 * This software is provided "as is," and the copyright holder makes no representations or warranties, express or
 * implied, including but not limited to warranties of merchantability or fitness for any particular purpose or that the
 * use of this software or documentation will not infringe any third party patents, copyrights, trademarks or other
 * rights.
 * 
 * The copyright holder will not be liable for any direct, indirect special or consequential damages arising out of any
 * use of this software or documentation.
 */
package com.bluewhalesystems.client.lwuit.richtext;

import java.util.Arrays;

import com.sun.lwuit.Font;
import com.sun.lwuit.plaf.Style;

import junit.framework.TestCase;

public final class FormattedDataControlSequenceTest extends TestCase
{
    public void testReadWriteFont()
    {
        System.out.println( "testReadWriteFont" );

        try
        {
            int[] beforeFont = null;
            int[] afterFont = new int[3];
            GrowableCharArray data = new GrowableCharArray();

            for( int index = 0; index < FONTS.length; ++index )
            {
                data.clear();
                beforeFont = FONTS[index];
                FormattedDataControlSequence.writeFont( beforeFont[0], beforeFont[1], beforeFont[2], data );
                FormattedDataControlSequence.readFont( afterFont, data.getArray(), 0 );
                assertTrue( "afterFont != beforeFont at index: " + index, fontEqual( afterFont, beforeFont ) );
            }
        }
        catch( Exception e )
        {
            e.printStackTrace();
            fail();
        }
    }

    public void testReadWriteInt()
    {
        System.out.println( "testReadWriteInt" );

        try
        {
            int beforeValue = 0;
            int afterValue = 0;
            GrowableCharArray data = new GrowableCharArray();

            for( int index = 0; index < INTS.length; ++index )
            {
                data.clear();
                beforeValue = INTS[index];
                FormattedDataControlSequence.writeInt( beforeValue, data );
                afterValue = FormattedDataControlSequence.readInt( data.getArray(), 0 );
                assertTrue( "afterValue != beforeValue at index: " + index, afterValue == beforeValue );
            }
        }
        catch( Exception e )
        {
            e.printStackTrace();
            fail();
        }
    }

    public void testCreationOfEdgeCases()
    {
        System.out.println( "testCreationOfEdgeCases" );

        try
        {
            FormattedDataControlSequence sequence = new FormattedDataControlSequence();

            sequence.initialize( null, null, null, FormattedDataControlSequence.FLAG_DO_NOT_ENCODE_FONT_OR_COLORS, null );
            assertTrue( "length does not match at index: 0", 2 == sequence.getLength() );

            sequence.initialize( new Style(), new Style(), null, FormattedDataControlSequence.FLAG_DO_NOT_ENCODE_FONT_OR_COLORS, null );
            assertTrue( "length does not match at index: 1", 2 == sequence.getLength() );

            sequence.initialize( null, null, null, FormattedDataControlSequence.FLAG_ENCODE_FONT | FormattedDataControlSequence.FLAG_ENCODE_COLORS, null );
            assertTrue( "length does not match at index: 2", 2 == sequence.getLength() );

            char[] cookie = "Cookie".toCharArray();
            sequence.initialize( null, null, null, FormattedDataControlSequence.FLAG_ENCODE_FONT | FormattedDataControlSequence.FLAG_ENCODE_COLORS, cookie );
            assertTrue( "length does not match at index: 3", 4 + cookie.length == sequence.getLength() );
        }
        catch( Exception e )
        {
            e.printStackTrace();
            fail();
        }
    }

    public void testCreation()
    {
        System.out.println( "testCreation" );

        try
        {
            GrowableCharArray data = new GrowableCharArray();
            int[] values = null;
            char[] cookie = null;
            int flags = 0;
            int[] outputValues = new int[7];
            char[] outputCookie = null;
            int length = 0;

            for( int index = 0; index < CREATION_VALUES_INPUT.length; ++index )
            {
                values = CREATION_VALUES_INPUT[index];
                cookie = CREATION_COOKIE_INPUT[index];
                flags = CREATION_FLAGS_INPUT[index];

                data.clear();
                Arrays.fill( outputValues, 0 );
                outputCookie = null;
                length = 0;

                length = FormattedDataControlSequence.writeSequence( values[0], values[1], values[2], values[3], values[4], values[5], values[6], cookie, flags, data );
                //System.out.println( "chars  <" + toBinary( data.getArray(), 0, data.length() ) + ">" );
                assertTrue( "length does not match at index: " + index, CREATION_LENGTH_OUTPUT[index] == length );

                outputCookie = FormattedDataControlSequence.readSequence( outputValues, null, null, data.getArray(), 0 );
                assertTrue( "cookies do not match at index: " + index, null == cookie ? null == outputCookie : Arrays.equals( outputCookie, cookie ) );
                assertTrue( "values do not match at index: " + index, Arrays.equals( outputValues, values ) );
            }
        }
        catch( Exception e )
        {
            e.printStackTrace();
            fail();
        }
    }

    private static final int[]    INTS                   = { 0x00, 0xFFFFFFFF, 0x12345678, 0x333333F3 };
    private static final int[][]  FONTS                  = { { Font.FACE_SYSTEM, Font.STYLE_PLAIN, Font.SIZE_MEDIUM }, { Font.FACE_SYSTEM, Font.STYLE_BOLD, Font.SIZE_LARGE },
            { Font.FACE_MONOSPACE, Font.STYLE_UNDERLINED | Font.STYLE_ITALIC, Font.SIZE_MEDIUM }, { Font.FACE_PROPORTIONAL, Font.STYLE_BOLD, Font.SIZE_SMALL } };

    private static final int[][]  CREATION_VALUES_INPUT  = { { Font.FACE_SYSTEM, Font.STYLE_PLAIN, Font.SIZE_MEDIUM, 0, 0, 0, 0 },
            { Font.FACE_SYSTEM, Font.STYLE_BOLD, Font.SIZE_LARGE, 0x00FFFFFF, 0x00FF0000, 0, 0 },
            { Font.FACE_PROPORTIONAL, Font.STYLE_UNDERLINED | Font.STYLE_ITALIC, Font.SIZE_SMALL, 0x00FFFFFF, 0x00FF0000, 0x00AA0000, 0x00FFFFFF }, { 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0 } };
    private static final char[][] CREATION_COOKIE_INPUT  = { null, null, "Cookie".toCharArray(), "Cookie 2".toCharArray(), null };
    private static final int[]    CREATION_FLAGS_INPUT   = {
            FormattedDataControlSequence.FLAG_INCLUDES_FONT,
            FormattedDataControlSequence.FLAG_INCLUDES_FONT | FormattedDataControlSequence.FLAG_INCLUDES_COLORS,
            FormattedDataControlSequence.FLAG_INCLUDES_FONT | FormattedDataControlSequence.FLAG_INCLUDES_COLORS | FormattedDataControlSequence.FLAG_INCLUDES_SELECTED_COLORS
                    | FormattedDataControlSequence.FLAG_INCLUDES_COOKIE, FormattedDataControlSequence.FLAG_INCLUDES_COOKIE, FormattedDataControlSequence.FLAG_INCLUDES_NOTHING };
    private static final int[]    CREATION_LENGTH_OUTPUT = { 4, 8, 19, 12, 2 };

    static boolean fontEqual( int[] aFontA, int[] aFontB )
    {
        if( null != aFontA && null != aFontB )
        {
            return Arrays.equals( aFontA, aFontB );
        }

        return aFontA == aFontB;
    }

    static String toBinary( char[] aData, int aOffset, int aCount )
    {
        StringBuffer buffer = new StringBuffer();

        for( int index = aOffset; index < aOffset + aCount; ++index )
        {
            buffer.append( toBinary( aData[index], 16 ) );

            if( index < aOffset + aCount - 1 )
            {
                buffer.append( ", " );
            }
        }

        return buffer.toString();
    }

    static String toBinary( long aValue, int aBitCount )
    {
        char[] chars = new char[aBitCount];

        for( int index = aBitCount - 1; index >= 0; index-- )
        {
            chars[index] = ( 1 == ( aValue & 1 ) ? '1' : '0' );
            aValue >>= 1;
        }

        return new String( chars );
    }
}